package ikelib;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Comparator;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.TreeSet;


public class wintime implements Comparable<wintime> {
	
	static int[][] Days = new int[100][12]; 
	static boolean DaysInitialized = false;
	static final int EpochYear = 1970;
	static final int LeapSecondMax = 10;
	
	static final int LeapSecInfoMax = 30;
	// うるう秒を扱う
	// 
	//static TreeSet LeapDay = new TreeSet();	// Leap day by UTC
	static LeapControl[] LeapSecInfo = new LeapControl[LeapSecInfoMax]; // Leap second(-1,0,1) = [index][0=june/1=dec]
	static int LeapSecInfoNum = 0;
	static int     LocalTimeOffsetHour = 9;		// Localtime offset LocalTime=UTC+Offset;
	static String LeapFile = "leapinfo.ini";

	static int     LocalTimeOffsetMinute = 0;		// Localtime offset LocalTime=UTC+Offset;
	static boolean LeapSecondEnable = false;
	//
	//
	//  // Leap second table
	//  UTC=9;
	//  // year , june , december
	//  1994, 	1,0
	//　  1995, 	0,1
	//	1997, 	1,0
	//	1998, 	0,1
	//	2005, 	0,1
	//	2008, 	0,1
	//	2012, 	1,0
	//-------------------------------
	//
	public class LeapControl {
		public int year;
		public int month;
		public int leap;
		public int offset;
		public long leapTime; 	// うるう秒が挿入、削除される時刻（秒） うるう秒を考慮しないで日付から計算される経過秒数で表す。
							 	//　示す時刻は、挿入、削除されたうるう秒の次の秒つまり、7/1 00:00:00+Offset 
								// または 翌年の1/1 00:00:00+Offsetを表すことにする 
		LeapControl(){
			year = 0; 
			month = 0;
			leap = 0;
			offset=0;
			leapTime = 0L;
		}
	}
	//
	//
	//  年、月、うるう秒からうるう秒時刻情報を作成する
	//  Epochからの経過秒数
	//
	private long getLeapSecInfo(int year,int month){
		int day=1;
		if(month==6){
			month = 7;
		}
		else if(month==12){
			year++;
			month = 1;
		}
		else{
			return 0L;
		}
		wintime wt = new wintime(year,month,day,0,0,0); // うるう秒が挿入、削除されれる秒の次の秒を示す。
		wt.add_hour(LocalTimeOffsetHour); // ローカルタイム
		wt.add_min(LocalTimeOffsetMinute); // ローカルタイム
		return wt.calcSimpleValueS();
	}
	/**
	 * うるう秒データを初期化する
	 */
	private void InitLeapSecondInfo(){
	    try {
            FileReader fr = new FileReader(LeapFile);
            BufferedReader br = new BufferedReader(fr);
            String line;
            LeapSecInfoNum= 0;
            int offset  = 0;
            while ((line = br.readLine()) != null && (LeapSecInfoNum<LeapSecInfoMax)) {
                line = line.trim();
                if(line.length()==0) continue;
            	String[] str = line.split("//");// コメント行以下を削除
                if(str.length==0) continue;
            	String s = str[0].trim();
                if(s.length()==0) continue;
                String[] tok=s.split("=");
                if(tok.length>=2){
                	if(tok[0].compareToIgnoreCase("UTC")==0){
                		int utc = 0;
                		try{
                			utc = Integer.valueOf(tok[1]);
                       		LocalTimeOffsetHour=utc;
                       	}
                		catch(NumberFormatException e){
                			System.err.format(LeapFile,": Irregal format : ",s);
                		}
                	}
                }
                else{ // A=Bでないタイプ
                	String[] numstr = s.split(",");
                	if(numstr.length!=3){
            			System.err.format(LeapFile,": Invalid line :",s);
            			continue;
                	}
                   	int year = 0;
                   	int jun = 0;
                   	int dec= 0;
                    try{
                  		LeapControl lc = new LeapControl();
                        lc.year = Integer.valueOf(numstr[0].trim());
                        lc.month = Integer.valueOf(numstr[1].trim());
                        lc.leap = Integer.valueOf(numstr[2].trim());
                        offset += lc.leap;
                        lc.offset = offset;
                        lc.leapTime = getLeapSecInfo(lc.year,lc.month);
                   		LeapSecInfo[LeapSecInfoNum]=lc;
                   		LeapSecInfoNum++;                   		
                	}
               		catch(NumberFormatException e){
            			System.err.format(LeapFile,": Irregal format : ",s);
            		}
               }
            }
            br.close();
            fr.close();
        } catch (IOException e) {
        	LeapSecondEnable = false;
        }
    
	}
	
	private void Initialize(){
		int d = 0;
		for(int y=0;y<100;y++){
			for(int m=0;m<12;m++){
				int yr = EpochYear+y;
				Days[y][m]=d;
				d += dayOfMonth(yr,m+1);
			}
		}
		DaysInitialized=true;
		
		// うるう秒を扱う
		InitLeapSecondInfo();
		
	}
	//-------------------------------
	// y : 1970,1971,...2069
	// m : 1,2,..12
	// d : 1,2,...
	private int getDays(int y,int m,int d){
		if(y<EpochYear) return 0;
		if(m<1 || m>12) return 0;
		return Days[y-EpochYear][m-1] + d;
	}
	/**
	 * 1970/1/1からの経過日を返す
	 * @return
	 */
	public int getDays(){
		return getDays(m_year,m_month,m_day);
	}
	/**
	 * 年初からの経過日を返す
	 * 1/1 = 1 1/2=2....
	 * @return
	 */
	public int getDayOfYear(){
		int days = getDays(m_year,m_month,m_day);
		int days2 = getDays(m_year,1,1);
		return days-days2+1;
	}
	//-------------------------------
	public wintime(){
		m_year=0;
		m_month=m_day=1;
		m_hour=m_min=m_sec=0;
		m_msec =0;
		m_usec = 0;
		if(!DaysInitialized) Initialize();
	}
	/**
	 * 有効かどうかを返す
	 * @return
	 */
	public boolean isValid(){
		if(m_year==0 && m_month ==1 && m_day==1 && m_hour==0 && m_min==0 && m_sec==0 && m_msec==0) return false;
		return true;
	}
	/**
	 * bcdからwintimeを構築する
	 * @param winbcd　byte[] bcdを含む配列
	 * @param offset　int winbcd[offset].. がbcdコード
	 */
	public wintime(byte[] winbcd,int offset){
		setwintime(winbcd,offset);
	}
	/**
	 * bcdからwintimeを構築する
	 * @param winbcd byte[] bcdを表す配列
	 */
	public wintime(byte[] winbcd){
		setwintime(winbcd,0);
	}
	/**
	 * EpockYeaｒ(1970/1/1)からの秒数で時刻をセットする。
	 * @param second　
	 */
	public void setTime(int second){
		int d = second/(60*60*24);
		int py = 0;
		int pm = 0;
		for(int y=0;y<100;y++){
			for(int m=0;m<12;m++){
				int days = Days[y][m];
				if(days > d) break; 
				py = y;
				pm = m;
			}
		}
		m_year  = py + EpochYear;
		m_month =  pm + 1;
		d -= Days[py][pm];
		m_day = d;
		d = getDays(m_year,m_month,m_day);
		second -=  d*(60*60*24);
		m_hour 	=  second / (60*60);
		second  -= m_hour * (60*60);
		m_min 	=  second /  60;
		second 	-= m_min * 60;
		m_sec 	=  second;
	}
	/**
	 * EpockYeaｒ(1970/1/1)からの秒数からwintimeを作成する
	 * @param second
	 */
	public wintime(int second){
		setTime(second);
	}
	/**
	 * EpockYeaｒ(1970/1/1)からのマイクロ秒数で時刻を構築
	 * @param second
	 */
	public wintime(double microsec){
		int sec = (int)(microsec/1e6);
		setTime(sec);
		double d = microsec - sec*1e6; // micro second
		int mic = (int)(d+0.5);// micro second;
		m_msec = mic / 1000;
		m_usec = mic % 1000;
	}
//	wintime(int sec,int msec){
//		year=0;
//		month=day=1;
//		hour=min=sec=0;
//		msec =0;
//		inc_sec(sec);
//		inc_msec(msec);
//	}
	/**
	 * bcdで時刻をセット
	 * @param winbcd　byte[] 
	 * @param offset winbcd[offse]がbcdコード
	 */
	private void setwintime(byte[] winbcd, int offset) {
		m_year  = bcd2int( winbcd[offset+0])+2000;
		if(m_year>=2070) m_year -= 100;
		m_month = bcd2int( winbcd[offset+1]);
		m_day   = bcd2int( winbcd[offset+2]);
		m_hour  = bcd2int( winbcd[offset+3]);
		m_min   = bcd2int( winbcd[offset+4]);
		m_sec   = bcd2int( winbcd[offset+5]);
		m_msec = 0;
		m_usec = 0;
	}
	/**
	 * wintimeから構築する
	 * @param tm
	 */
	public wintime(wintime tm){
		m_year = tm.m_year;
		m_month = tm.m_month;
		m_day = tm.m_day;
		m_hour = tm.m_hour;
		m_min = tm.m_min;
		m_sec = tm.m_sec;
		m_msec = tm.m_msec;
		m_usec = tm.m_usec;
	}
	/**
	 * 年月日からwintimeを構成
	 * @param y　年
	 * @param m　月
	 * @param d　日
	 * @param h　時
	 * @param mi　分
	 * @param se　秒
	 */
	public wintime(int y,int m,int d,int h,int mi,int se){
		m_year = y;
		m_month = m;
		m_day = d;
		m_hour = h;
		m_min = mi;
		m_sec = se;
	}
	/**
	 * 年月日からwintimeを構成
	 * 
	 * @param y
	 * @param m
	 * @param d
	 * @param h
	 * @param mi
	 * @param se
	 * @param ms ミリ秒
	 */
	public wintime(int y,int m,int d,int h,int mi,int se,int ms){
		m_year = y;
		m_month = m;
		m_day = d;
		m_hour = h;
		m_min = mi;
		m_sec = se;
		m_msec = ms;
	}
	/**
	 * 文字列からwintimeをつくる
	 * 　 サポートしている形式　
	 * 1) 　2013/1/2 13:45:59
	 * 2) 2013/1/2 13:45'59
	 * 
	 * @param time String
	 * @return boolean 成功・不成功
	 */
	public boolean setTime(String time) {
		
		String[] tok = time.split("[/ :'.]");
		if(tok.length>=6){
			try{
				m_year = Integer.valueOf(tok[0]);
				m_month = Integer.valueOf(tok[1]);
				m_day = Integer.valueOf(tok[2]);
				m_hour = Integer.valueOf(tok[3]);
				m_min = Integer.valueOf(tok[4]);
				m_sec = Integer.valueOf(tok[5]);
				m_msec = 0;
				
			} catch(NumberFormatException e){
				e.printStackTrace();
				return false;
			}
			return true;
		}
		return false;
	}
	/**
	 * １byteのbcdをintに変換
	 * @param bcd　byte
　	 * @return 
	 */
	static public int bcd2int(byte bcd){
		int lo,hi;
		lo = bcd & 0xf;
		hi = (bcd >> 4) & 0xf;
		return lo + hi*10;
	}
	/**
	 * intをbcd（２ケタ）コードへ
	 * @param num　(00..99)
	 * @return byte
	 */
	private byte int2bcd(int num){
		int lo,hi;
		lo = num % 10;
		hi = num /10;
		byte ret = (byte)(hi * 16 + lo);
		return ret;
	}
	/**
	 * bcd[6]を返す
	 * @return　
	 */
	public byte[] getBcd(){
		byte[] ret = new byte[6];
		//ret[0] = int2bcd(m_year-EpochYear);
		if(m_year>=2000) {	// 手抜き
			ret[0] = int2bcd(m_year-2000);
		}
		else{
			ret[0] = int2bcd(m_year-1900);
		}
		ret[1] = int2bcd(m_month);
		ret[2] = int2bcd(m_day);
		ret[3] = int2bcd(m_hour);
		ret[4] = int2bcd(m_min);
		ret[5] = int2bcd(m_sec);
		return ret;
	}
	/**
	 * （bcd[]の)長さを返す
	 * @return
	 */
	public int length(){
		return 6;
	}
	/**
	 * yearを返す
	 * @return
	 */
	public int year(){ return m_year; }
	/**
	 * monthを返す
	 * @return
	 */
	public int month(){ return m_month; }
	/**
	 * dayを返す
	 * @return
	 */
	public int day(){ return m_day; }
	/**
	 * hourを返す
	 * @return
	 */
	public int hour(){ return m_hour; }
	/**
	 * minutesを返す
	 * @return
	 */
	public int min(){ return m_min; }
	/**
	 * secondを返す。
	 * @return
	 */
	public int sec(){ return m_sec; }
	/**
	 * ミリsecondを返す
	 * @return
	 */
	public int msec(){ return m_msec; }
	/**
	 * マイクロsecondを返す
	 * @return
	 */
	public int usec(){ return m_usec; }
	/**
	 * 年を＋１する
	 */
	public void inc_year(){
		m_year++;
	}
	/**
	 * 年を-1する
	 */
	public void dec_year(){
		m_year--;
	}
	/**
	 * month を+1する
	 */
	public void inc_month(){
		if(++m_month > 12){
			m_month = 1;
			inc_year();
		}
	}
	/**
	 * month を-1する
	 */
	public void dec_month(){
		if(--m_month < 1){
			m_month = 12;
			dec_year();
		}
	}
	/**
	 * うるう年かどうかを調べる
	 * @param year
	 * @return
	 */
	private static boolean isLeapYear(int year){
		if((year % 4)==0 && (year % 100)!=0 && (year % 400)==0) return true;
		return false;
	}
	/**
	 * 月の最大日を得る
	 * @param year
	 * @param month
	 * @return
	 */
	private static int dayOfMonth(int year,int month){
		int max;
		switch(month){
		case 1:	max=31; break;
		case 2:
			if(isLeapYear(year)) 	max = 29;
			else					max=28; 
			break;
		case 3:	max=31; break;
		case 4:	max=30; break;
		case 5:	max=31; break;
		case 6:	max=30; break;
		case 7:	max=31; break;
		case 8:	max=31; break;
		case 9:	max=30; break;
		case 10:	max=31; break;
		case 11:	max=30; break;
		default:	max=31; break;
		}
		return max;
	}
	/**
	 * 日を＋１する
	 */
	public void inc_day(){
		m_day++;
		int max = dayOfMonth(m_year,m_month);
		if(m_day > max){
			m_day = 1;
			inc_month();
		}
	}
	/**
	 * 日を-１する
	 */
	public void dec_day(){
		m_day--;
		if(m_day < 1){
			dec_month();
			m_day = dayOfMonth(m_year,m_month);
		}
	}
	/**
	 * 時を+1する
	 */
	public void inc_hour(){
		if(++m_hour >= 24){
			m_hour=0;
			inc_day();
		}
	}
	/**
	 * 時に時を加える
	 * @param hour 加える時間
	 */
	public void add_hour(int hour){
		if(hour>0) {
			for(int i=0;i<hour;i++) inc_hour();
		}
		else if(hour<0){
			for(int i=0;i>hour;i--) dec_hour();
		}
	}
	/**
	 * 時を-1する
	 */
	public void dec_hour(){
		if(--m_hour < 0){
			m_hour=23;
			dec_day();
		}
	}
	/**
	 * 分に分を加える　
	 * @param minute　加えたい分
	 */
	public void add_min(int minute){
		if(minute>0) {
			for(int i=0;i<minute;i++) inc_min();
		}
		else if(minute<0){
			for(int i=0;i>minute;i--) dec_min();
		}
	}
	/**
	 * 分を＋１する
	 */
	public void inc_min(){
		if(++m_min >= 60){
			m_min=0;
			inc_hour();
		}
	}
	/**
	 * 分を-1する
	 */
	public void dec_min(){
		if(--m_min < 0){
			m_min=59;
			dec_hour();
		}
	}
	/**
	 * 秒を＋１する
	 */
	public void inc_sec(){
		if(++m_sec>=60){
			m_sec=0;
			inc_min();
		}
	}
	/**
	 * 秒を-1する
	 */
	public void dec_sec(){
		if(--m_sec < 0){
			m_sec=59;
			dec_min();
		}
	}
	/**
	 * ミリ秒を＋１する
	 */
	public void inc_msec(){
		if(++m_msec>=1000){
			m_msec=0;
			inc_sec();
		}
	}
	/**
	 * ミリ秒を-1する
	 */
	public void dec_msec(){
		if(--m_msec<0){
			m_msec=9999;
			dec_sec();
		}
	}
	/**
	 * 時間を進める
	 * @param hu　hour
	 * @param mi minute
	 * @param se second
	 * @param ms milli second
	 */
	public void add_time(int hu,int mi,int se,int ms){
		m_msec += ms;
		if(m_msec>=1000){
			m_msec -= 1000;
			inc_sec();
		}
		m_sec += se;
		if(m_sec >= 60){
			m_sec -= 60;
			inc_min();
		}
		m_min += mi;
		if(m_min>=60){
			m_min -= 60;
			inc_hour();
		}
		m_hour += hu;
		if(m_hour >= 24){
			m_hour -= 24;
			inc_day();
		}
	}
	/**
	 * 時間を戻す
	 * @param hu　hour
	 * @param mi minute
	 * @param se second
	 * @param ms milli second
	 */
	public void sub_time(int hu,int mi,int se,int ms){
		m_msec -= ms;
		if(m_msec<0){
			m_msec += 1000;
			dec_sec();
		}
		m_sec -= se;
		if(m_sec < 0){
			m_sec += 60;
			dec_min();
		}
		m_min -= mi;
		if(m_min<0){
			m_min += 60;
			dec_hour();
		}
		m_hour -= hu;
		if(m_hour < 0){
			m_hour += 24;
			dec_day();
		}
	}
//	public void sub_time(wintime st){
//		long sl = st.getValue();
//		this.dec_msec(sl);
//	}
	/**
	 * 秒に秒を加える
	 * @param second 加える秒数
	 */
	public void inc_sec(int second){
		if(second<0){
			dec_sec(-second);
			return; 
		}
		int hu,mi,se;
		//assert(ms<1000*60*60*24);
		while(second>=60*60*24){
			inc_day();
			second -= 60*60*24;
		}
		hu = second / (60*60);
		second %= (60*60);
		mi = second / (60);
		second %= (60);
		se = second;
		add_time(hu,mi,se,0);
	}
	/**
	 * 秒を引く
	 * @param second　引く秒数
	 */
	public void dec_sec(int second){
		if(second<0){
			inc_sec(-second);
			return;
		}
		int hu,mi,se;
		//assert(ms<1000*60*60*24);
		while(second>=60*60*24){
			dec_day();
			second -= 60*60*24;
		}
		hu = second / (60*60);
		second %= (60*60);
		mi = second / (60);
		second %= (60);
		se = second;
		sub_time(hu,mi,se,0);
	}
	/**
	 * ミリ秒を加える
	 * @param ms　加えるミリ秒
	 */
	public void inc_msec(long ms){
		long hu,mi,se;
		//assert(ms<1000*60*60*24);
		while(ms>=1000*60*60*24L){
			inc_day();
			ms -= 1000*60*60*24L;
		}
		hu = (ms / (1000*60*60L));
		ms = (ms % (1000*60*60L));
		mi = (ms / (1000*60L));
		ms = (ms % (1000*60L));
		se = (ms / 1000L);
		ms = (ms % 1000L);
		add_time((int)hu,(int)mi,(int)se,(int)ms);
	}
	/**
	 * ミリ秒を引く
	 * @param ms　引くミリ秒
	 */
	public void dec_msec(long ms){
		long hu,mi,se;
		//assert(ms<1000*60*60*24);
		while(ms>=1000*60*60*24L){
			dec_day();
			ms -= 1000*60*60*24L;
		}
		hu = (ms / (1000*60*60L));
		ms = (ms % (1000*60*60L));
		mi = (ms / (1000*60L));
		ms = (ms % (1000*60L));
		se = (ms / 1000L);
		ms = (ms % 1000L);
		sub_time((int)hu,(int)mi,(int)se,(int)ms);
	}
	/**
	 * マイクロ秒単位で時刻を返す
	 * @return　long マイクロ秒
	 */
	public  long getValueU(){
//		return (long)((long)(m_year-EpochYear) * (long)(12*31*24*60*60*1000L)) + (long)((long)(m_month-1)*(long)(31*24*60*60*1000L)) + 
//		(long)((long)(m_day-1)*(long)(24*60*60*1000L)) + (long)((long)m_hour*(long)(60*60*1000L)) + (long)((long)m_min*(long)(60*1000)) + 
//		(long)((long)m_sec*(1000)) + (long)m_msec;
		long ret = getValue() * 1000L;
		ret += m_usec;
		return ret;
	}
	/**
	 * ミリ秒単位で時刻を返す
	 * @return　long
	 */
	public  long getValue(){
//		return (long)((long)(m_year-EpochYear) * (long)(12*31*24*60*60*1000L)) + (long)((long)(m_month-1)*(long)(31*24*60*60*1000L)) + 
//		(long)((long)(m_day-1)*(long)(24*60*60*1000L)) + (long)((long)m_hour*(long)(60*60*1000L)) + (long)((long)m_min*(long)(60*1000)) + 
//		(long)((long)m_sec*(1000)) + (long)m_msec;
		
		return (long)getValueS()*1000L +  m_msec;
		//long days = getDays(m_year,m_month,m_day);
		//return days*(24*60*60*1000L) + (long)((long)m_hour*(long)(60*60*1000L)) + (long)((long)m_min*(long)(60*1000)) + (long)((long)m_sec*(1000)) + (long)m_msec;
	}
	/**
	 * 
	 * @param secValue
	 * @return
	 */
	private int getLeapOffset(int simpleValue){
		int i = LeapSecInfoNum -1 ;
		for(;i>=0;i--){
			LeapControl lc = LeapSecInfo[i];
			if(simpleValue>=lc.leapTime){
				return lc.offset;
			}
		}
		return 0;
   }
	/**
	 * 
	 * @return
	 */
	private int calcSimpleValueS(){
		long days = getDays(m_year,m_month,m_day);
		long sec = days*(24*60*60L) + (long)((long)m_hour*(long)(60*60L)) + (long)((long)m_min*(long)(60)) + (long)m_sec*(1);
		return (int)sec;
	}
	/**
	 * 秒単位で時刻を返す
	 * @return 秒数
	 */
	public  int getValueS(){
//		return (m_year-EpochYear) * (12*31*24*60*60) + (m_month-1)*(31*24*60*60) + 
//		(m_day-1)*(24*60*60) + m_hour*(60*60) + m_min*(60) + m_sec*(1) ;
//		long days = getDays(m_year,m_month,m_day);
//		long sec = days*(24*60*60L) + (long)((long)m_hour*(long)(60*60L)) + (long)((long)m_min*(long)(60)) + (long)m_sec*(1);
//		return (int)sec;
		int ret = calcSimpleValueS();
		if(LeapSecondEnable){ // うるう秒補正を行う
			//ret += getLeapOffset(ret);
		}
		return ret;
	}
	
	/**
	 * wintimeを比較する
	 * @param t　比較対象　
	 * @return　this - t を返す。
	 */
	public int compare(wintime t){
		int t1 = getValueS();
		int t2 = t.getValueS();
		return t1 - t2;
	}
	/**
	 * "%4d/%02d/%02d %02d:%02d:%02d",m_year,m_month,m_day,m_hour,m_min,m_sec
	 * @return　String
	 */
	public String fmt(){
		String ret = String.format("%4d/%02d/%02d %02d:%02d:%02d",m_year,m_month,m_day,m_hour,m_min,m_sec);
		return ret;
	}
	/**
	 * "%04d%02d%02d%02d%02d%02d",m_year,m_month,m_day,m_hour,m_min,m_sec
	 * @return String
	 */
	public String fmt2(){
		String ret = String.format("%04d%02d%02d%02d%02d%02d",m_year,m_month,m_day,m_hour,m_min,m_sec);
		return ret;
	}
	/**
	 * "%04d%02d%02d %02d%02d%02d.%03d.%03d",m_year,m_month,m_day,m_hour,m_min,m_sec,m_msec,m_usec
	 * @return String
	 */
	public String fmtFull(){
		String ret = String.format("%04d/%02d/%02d %02d:%02d:%02d.%03d.%03d",m_year,m_month,m_day,m_hour,m_min,m_sec,m_msec,m_usec);
		return ret;
	}
	/**
	 * "%4d/%02d/%02d",m_year,m_month,m_day
	 * @return String
	 */
	public String fmtDay(){
		String ret = String.format("%4d/%02d/%02d",m_year,m_month,m_day);
		return ret;
	}
	/**
	 * "%02d:%02d:%02d",m_hour,m_min,m_sec
	 * @return String
	 */
	public String fmtSec(){
		String ret = String.format("%02d:%02d:%02d",m_hour,m_min,m_sec);
		return ret;
	}
	/**
	 * "%02d:%02d:%02d.%03d",m_hour,m_min,m_sec,m_msec
	 * @return
	 */
	public String fmtmSec(){
		String ret = String.format("%02d:%02d:%02d.%03d",m_hour,m_min,m_sec,m_msec);
		return ret;
	}
	/**
	 * "%02d:%02d:%02d.%03d.%03d",m_hour,m_min,m_sec,m_msec,m_usec
	 * @return String
	 */
	public String fmtuSec(){
		String ret = String.format("%02d:%02d:%02d.%03d.%03d",m_hour,m_min,m_sec,m_msec,m_usec);
		return ret;
	}
	/**
	 * "%02d%02d%02d%02d.%02d",m_year-2000,m_month,m_day,m_hour,m_min,m_sec
	 * @return String
	 */
	public String fmtMinutFileName(){
		String ret;
		if(m_year < 2000) {
			 ret = String.format("%02d%02d%02d%02d.%02d",m_year-1900,m_month,m_day,m_hour,m_min,m_sec);
		}
		else{
			ret = String.format("%02d%02d%02d%02d.%02d",m_year-2000,m_month,m_day,m_hour,m_min,m_sec);
		}
		return ret;
	}
	/**
	 * ファイル名に使える文字列を返す。
	 * "%02d%02d%02d%02d",m_year-1900,m_month,m_day,m_hour,m_min
	 * @return　　String
	 */
	public String fmtHourFileName(){
		String ret;
		if(m_year < 2000) {
			 ret = String.format("%02d%02d%02d%02d",m_year-1900,m_month,m_day,m_hour,m_min);
		}
		else{
			ret = String.format("%02d%02d%02d%02d",m_year-2000,m_month,m_day,m_hour,m_min);
		}
		return ret;
	}
	private int m_year;
	private int m_month;
	private int m_day;
	private int m_hour;
	private int m_min;
	private int m_sec;
	private int m_msec;
	private int m_usec;
	private int m_usecPrs;
	/**
	 * ミリ秒をセットする
	 * @param ms ミリ秒
	 */
	public void setMSec(int ms){
		m_msec = ms;
	}
	/**
	 * マイクロ秒をセットする
	 * @param us
	 */
	public void setUSec(int us){
		m_usec = us;
	}
	
	@Override
	public int compareTo(wintime arg0) {
		long i1 = this.getValue();
		long i2 = arg0.getValue();
		return (int)(i1 - i2);
	}
	/**
	 * 1秒以下の時刻（小数点以下）を解釈する。
	 * 1 -> 100ms/us 01->10 001->1
	 * @param txt
	 * @return
	 */
	private int parseSubSec(String txt) throws NumberFormatException{
		int ret = 0;
		switch(txt.length()){
		case 1:
			ret = 100*Integer.valueOf(txt);
			break;
		case 2:
			ret = 10*Integer.valueOf(txt);
			break;
		case 3:
			ret = Integer.valueOf(txt);
			break;
		default:
			//ret = 0;
			//System.err.println("Error format of number - sub second length should be from 1 to 3: " + txt);
			throw new NumberFormatException();
		}
		return ret;
	}
	/**
	 * 59.001 の形式の時刻を解釈する 
	 * @param txt　String
	 * 		59.001 
	 * @return 
	 */
	private int parsemSec(String txt) throws NumberFormatException{
		String[] tok2 = txt.split("\\.");
		int s=m_sec;
		int m=m_msec;
		m_usecPrs=m_usec;
		switch(tok2.length){
		case 0:
			break;
		case 1:
			s=Integer.valueOf(tok2[0]);
			break;
		case 2:
			s=Integer.valueOf(tok2[0]);
			m=parseSubSec(tok2[1]);
			break;
		default:
			s=Integer.valueOf(tok2[0]);
			m=parseSubSec(tok2[1]);
			m_usecPrs=parseSubSec(tok2[2]);
			break;
		}
		if(s<0 || s>59 || m<0 || m>999 || m_usecPrs<0 || m_usecPrs>999){
			throw new NumberFormatException();
		}
		return s*0x400 + m;
	}
	/**
	 * 0:23:59 の形式の時刻を解釈する
	 * 時、分を省略可能とする
	 * @param txt
	 * @return 秒数を返す
	 */
	private int parseHMSMSec(String txt) throws NumberFormatException {
		String[] tok2 = txt.split(":");
		int h=m_hour;
		int m=m_min;
		int ms=m_sec;
		switch(tok2.length){
		case 0:
			break;
		case 1:
			ms=parsemSec(tok2[0]);
			break;
		case 2:
			m =Integer.valueOf(tok2[0]);
			ms =parsemSec(tok2[1]);
			break;
		default:
			h =Integer.valueOf(tok2[0]);
			m =Integer.valueOf(tok2[1]);
			ms =parsemSec(tok2[2]);
			break;
		}
		if(ms<0 || m<0 || m>59 || h<0 || h>23){
			throw new NumberFormatException();
		}
		return ms + m*0x10000 + h*0x1000000;
	}
	/**
	* 2011/5/30 のような日付文字列を解釈する。
	* 年、月を省略可能とする。　2 = 2日　12/31 12月31日
	 * 
	 * @param txt String
	 * @return Epochからの日数を返す。
	 * @throws NumberFormatException
	 */
	private int parseDay(String txt) throws NumberFormatException {
		String[] tok2 = txt.split("/");
		int y=m_year;
		int m=m_month;
		int d=m_day;
		switch(tok2.length){
		case 0:
			break;
		case 1:
			d=Integer.valueOf(tok2[0]);
			break;
		case 2:
			m =Integer.valueOf(tok2[0]);
			d=Integer.valueOf(tok2[1]);
			break;
		default:
			y =Integer.valueOf(tok2[0]);
			m =Integer.valueOf(tok2[1]);
			d=Integer.valueOf(tok2[2]);
			break;
		}
		if(y<1900) y += 2000;
		if( m <= 0 || m>12 || d<=0 || d>31){
			throw new NumberFormatException();
		}
		return d + m*0x100 + y*0x10000;
	}
	/**
	 * 時刻を表す文字列Y/M/D h:m:s.ms.usからwintimeを作る
	 * @param txt
	 * @return　bit0:h:m:s.ms.usを持っていた、bit1:Y/M/Dを持っていた
	 */
	public int parseDaySec(String txt) throws NumberFormatException{
		
		String[] tok2 = txt.trim().split(" ");
		int a=0;
		int b=0;
		int ret = 0;
		if(tok2.length >= 2){
			a=parseDay(tok2[0]);
			b=parseHMSMSec(tok2[1]);
		}
		else if(tok2.length == 1){
			b=parseHMSMSec(tok2[0]);
			if(b==0){
				a=parseDay(tok2[0]);
			}
		}
		if(a>=0){
			m_day = a & 0xff;
			m_month = (a >> 8) & 0xff;
			m_year = (a >> 16) & 0xfff;
			ret |= 0x02;
		}
		if(b>=0){
			m_usec = m_usecPrs;
			m_msec = b & 0x3ff;
			m_sec = (b >> 10) & 0x3f;
			m_min = (b >> 16) & 0xff;
			m_hour = (b >> 24) & 0xff;
			ret |= 0x01;
		}
		return ret;
	}
}
